package com.sunlands.zlcx.usercenter.controller;

import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Splitter;
import com.google.common.collect.Lists;
import com.sunlands.zlcx.usercenter.client.DeskMatePushService;
import com.sunlands.zlcx.usercenter.client.GroupInfoService;
import com.sunlands.zlcx.usercenter.client.bean.PushDTO;
import com.sunlands.zlcx.usercenter.common.annotation.AuthSig;
import com.sunlands.zlcx.usercenter.common.annotation.AutoLog;
import com.sunlands.zlcx.usercenter.common.cache.RedisDistributedLockImpl;
import com.sunlands.zlcx.usercenter.constant.*;
import com.sunlands.zlcx.usercenter.domain.*;
import com.sunlands.zlcx.usercenter.exception.CheckRunException;
import com.sunlands.zlcx.usercenter.exception.GlobalExceptionHandler;
import com.sunlands.zlcx.usercenter.exception.PlatformException;
import com.sunlands.zlcx.usercenter.repository.UsersRepository;
import com.sunlands.zlcx.usercenter.service.*;
import com.sunlands.zlcx.usercenter.service.status.common.AbstractStudyStatus;
import com.sunlands.zlcx.usercenter.util.*;
import com.sunlands.zlcx.usercenter.util.image.LogoConfig;
import com.sunlands.zlcx.usercenter.util.image.QrcodeFont;
import com.sunlands.zlcx.usercenter.util.image.QrcodeUtils;
import com.sunlands.zlcx.usercenter.vo.*;
import com.sunlands.zlcx.usercenter.vo.response.BusinessResult;
import com.sunlands.zlcx.usercenter.vo.response.PageResultVO;
import io.swagger.annotations.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.*;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.sunlands.zlcx.usercenter.common.annotation.AutoLog.Level.DEBUG;
import static com.sunlands.zlcx.usercenter.controller.UploadController.MODEL_PATH;
import static com.sunlands.zlcx.usercenter.domain.UsersDO.StatusEnums.LEARN_TIME_ROOM_LEARNING;
import static com.sunlands.zlcx.usercenter.domain.UsersStudyInfoDO.TypeEnums.ORDERNARY_COUNT_TIME;
import static com.sunlands.zlcx.usercenter.vo.CommonResultMessage.PARAMS_NOT_INVALIDE;
import static com.sunlands.zlcx.usercenter.vo.CommonResultMessage.USER_NOT_LEARNING;

/**
 * @author 郜炎峰
 * description: 学习目标
 */
@SuppressWarnings("unused")
@Api(tags = "5、学习生活信息", position = 5)
@ApiResponses(value = {@ApiResponse(code = 400, response = GlobalExceptionHandler.class, message = "数据校验失败"), @ApiResponse(code = 500, response = GlobalExceptionHandler.class, message = "内部错误")})
@Slf4j
@RestController
@RequestMapping("/study")
public class UsersStudyController implements AuthSupport {

    @Value("${url}")
    private String url;

    @ApiOperation(value = "学习计时,连麦计时", notes = "type:1学习计时结束,5连麦计时结束;11开始学习计时,13学习计时暂停,14学习计时继续,15开始连麦计时")
    @PostMapping("/user/add/timing")
    @AutoLog
    @PreAuthorize("isAuthenticated()")
    @AuthSig
    public BusinessResult addStudy(@ApiParam(required = true, value = "用户学习VO") @RequestBody UsersStudyInfoVO usersStudyInfoVO) {
        String checkAddStudy = checkAddStudy(usersStudyInfoVO);
        if (null != checkAddStudy) {
            throw new IllegalArgumentException(checkAddStudy);
        }
        Long userId = usersStudyInfoVO.getUserId();
        try {
            if (redisDistributedLock.openUserLock(userId)) {
                Boolean booleanFuture = usersStudyService.addUsersStudyInfo(usersStudyInfoVO);
                // 学习计时统计结果
                if (booleanFuture &&
                        UsersStudyInfoDO.TypeEnums.create(usersStudyInfoVO.getType()) == ORDERNARY_COUNT_TIME) {
                    //如果是连麦服务，没有进行手动触发结束学习的操作，但是需要查询此次连麦的学习记录，直接返回最近一次的学习记录
                    if (Objects.isNull(usersStudyInfoVO.getStudyMinuteSeconds())) {
                        usersStudyInfoVO = UsersStudyInfoVO.from(usersStudyService.findLatestStudyInfo(userId));
                    }
                    UsersLearningResultVO learningResult = usersStudyService.getLearningResult(usersStudyInfoVO);
                    return BusinessResult.createSuccessInstance(learningResult);
                }
            }
        } finally {
            redisDistributedLock.releaseUserLock(userId);
        }
        return BusinessResult.createSuccessInstance(null);
    }

//    @ApiOperation(value = "学习计时提醒时间设置", notes = "学习计时提醒时间设置")
//    @PostMapping("/set/time")
//    @AutoLog
//    @PreAuthorize("isAuthenticated()")
//    @AuthSig
//    public BusinessResult setStudyTime(@ApiParam(required = true, value = "时间,秒") @RequestParam Long setTime) {
//        try {
//            UsersDO usersDO = currentUsers(usersService);
//            if (null == usersDO.getId() || !LearningStatus.ifOrdernaryLearn(usersDO.getStatus())) {
//                return BusinessResult.createInstance(CommonResultMessage.INVALID_USER, "不是学习中的用户");
//            }
//            String key = RedisKeyConst.getUserSetLearnTime();
//            log.info("用户设定学习时间：key={}, userId={}, setTime={}", key, usersDO.getId(), setTime);
//            Boolean add = redisTemplate.opsForZSet().add(key, usersDO.getId(), setTime);
//            return BusinessResult.createSuccessInstance(add);
//        } catch (Exception ex) {
//            log.info(" user add timing error , ex = {}", ex);
//        }
//        return BusinessResult.createInstance(CommonResultMessage.UNKOWN_ERROR, "未知错误，请联系管理员");
//    }

//    @ApiOperation(value = "学习计时提醒时间取消", notes = "学习计时提醒时间取消")
//    @PostMapping("/cancle/time")
//    @AutoLog
//    @PreAuthorize("isAuthenticated()")
//    @AuthSig
//    public BusinessResult cancleStudyTime() {
//        try {
//            UsersDO usersDO = currentUsers(usersService);
//            if (null == usersDO.getId() || !LearningStatus.ifOrdernaryLearn(usersDO.getStatus())) {
//                return BusinessResult.createInstance(CommonResultMessage.INVALID_USER, "不是学习中的用户");
//            }
//            String key = RedisKeyConst.getUserSetLearnTime();
//            log.info("用户取消学习提醒：key={}, userId={}", key, usersDO.getId());
//            Long remove = redisTemplate.opsForZSet().remove(key, usersDO.getId());
//            return BusinessResult.createSuccessInstance(remove);
//        } catch (Exception ex) {
//            log.info(" user cancle timing error , ex = {}", ex);
//        }
//        return BusinessResult.createInstance(CommonResultMessage.UNKOWN_ERROR, "未知错误，请联系管理员");
//    }

    @ApiOperation(value = "获取学习计时名称的历史记录", notes = "type:1学习计时结束,5连麦计时结束;获取学习计时名称的历史记录")
    @GetMapping("/learn/name/history")
    @AutoLog(logLevel = DEBUG)
    @AuthSig
    public BusinessResult getLearnNameHistory() {
        Long currentUserId = currentUserId();
        if (null == currentUserId) {
            return BusinessResult.createInstance(CommonResultMessage.INVALID_USER);
        }
        try {
            List<UsersLearnNameHistoryDO> nameHistoryList = usersStudyService.getLearnNameHistory(currentUserId, 1, 6);
            if (AssertUtil.isEmpty(nameHistoryList)) {
                return BusinessResult.createSuccessInstance(new ArrayList<>(0));
            }
            Set<String> nameList = nameHistoryList.stream().map(n -> n.getLearnName()).collect(Collectors.toSet());
            return BusinessResult.createSuccessInstance(nameList);
        } catch (Exception ex) {
            log.info("learn name history error , ex = {}", ex);
        }
        return BusinessResult.createInstance(CommonResultMessage.UNKOWN_ERROR, "未知错误，请联系管理员");
    }

    @ApiOperation(value = "获取用户最近一条学习计时名称", notes = "获取用户最近一条学习计时名称")
    @GetMapping("/last/learn/name")
    @AutoLog(logLevel = DEBUG)
    @AuthSig
    public BusinessResult getLearnName() {
        UsersDO usersDO = currentUsers(usersService);
        if (null == usersDO) {
            return BusinessResult.createInstance(CommonResultMessage.INVALID_USER);
        }
        try {
            UsersLearnNameHistoryDO nameDO = usersStudyService.getLearnNameDO(usersDO.getId());
            return BusinessResult.createSuccessInstance(nameDO);
        } catch (Exception ex) {
            log.info("get learn name history error , ex = {}", ex);
        }
        return BusinessResult.createInstance(CommonResultMessage.UNKOWN_ERROR, "未知错误，请联系管理员");
    }


    @ApiOperation(value = "创建或修改学习计时名称", notes = "创建或修改学习计时名称")
    @PostMapping("/edit/learn/name")
    @AutoLog
    @AuthSig
    public BusinessResult saveLearnName(@ApiParam(required = true, value = "修改名字三个状态,学习之前:1, 学习中:2, 学习之后:3") @RequestParam Integer nameStatus,
                                        @ApiParam(required = true, value = "学习计时名称") @RequestParam String name) {
        UsersDO usersDO = currentUsers(usersService);
        if (null == usersDO) {
            return BusinessResult.createInstance(CommonResultMessage.INVALID_USER);
        }
        if (NameStatus.getLearningStatus(nameStatus) == null || StringUtil.isEmpty(name)) {
            return BusinessResult.createInstance(PARAMS_NOT_INVALIDE);
        }
        if (!LearningStatus.ifOrdernaryLearn(usersDO.getStatus()) && NameStatus.getLearningStatus(nameStatus) == NameStatus.LEARN_TIMING) {
            return BusinessResult.createInstance(PARAMS_NOT_INVALIDE, "名称状态和当前学习状态不一致");
        } else if (LearningStatus.ifOrdernaryLearn(usersDO.getStatus()) && NameStatus.getLearningStatus(nameStatus) != NameStatus.LEARN_TIMING) {
            return BusinessResult.createInstance(PARAMS_NOT_INVALIDE, "名称状态与当前学习状态不一致");
        }
        try {
            if (redisDistributedLock.openUserLock(usersDO.getId())) {
                return BusinessResult.createSuccessInstance(usersStudyService.saveLearnName(usersDO, nameStatus, name));
            }
        } catch (PlatformException ex) {
            log.error("", ex);
            return BusinessResult.createInstance(CommonResultMessage.UNKOWN_ERROR.code, ex.getMessage(), ex.getMessage());
        } catch (Exception ex) {
            log.error("", ex);
        } finally {
            redisDistributedLock.releaseUserLock(usersDO.getId());
        }
        return BusinessResult.createInstance(CommonResultMessage.UNKOWN_ERROR, "未知错误，请联系管理员");
    }

    @ApiOperation(value = "获取用户当前学习计时时间,单位秒，前端用", notes = "用户当前学习计时时间,未学习:1,学习计时中:2,学习计时暂停中:12," +
            "学习计时继续中:13")
    @GetMapping("/learnTime")
    @AutoLog(logLevel = DEBUG)
    @PreAuthorize("isAuthenticated()")
    @AuthSig
    public BusinessResult learnTime(HttpServletRequest request) {
        Long userId = currentUserId();
        if (null == userId) {
            return BusinessResult.createInstance(CommonResultMessage.INVALID_USER);
        }
        String version = Version.getVersion(request);
        JSONObject jsonObject = usersStudyService.getLearnTime(userId, version);
        return BusinessResult.createSuccessInstance(jsonObject);
    }

    @ApiOperation(value = "获取用户当前学习计时信息，前端用", notes = "用户当前学习计时信息,未学习:1,学习计时中:2,学习计时暂停中:12," +
            "学习计时继续中:13", response = UsersLearnInfoVO.class)
    @GetMapping("/learnInfo")
    @AutoLog(logLevel = DEBUG)
    @PreAuthorize("isAuthenticated()")
    @AuthSig
    public BusinessResult learnInfo(HttpServletRequest request) {
        Long userId = currentUserId();
        if (null == userId) {
            return BusinessResult.createInstance(CommonResultMessage.INVALID_USER);
        }
        JSONObject jsonObject = usersStudyService.getLearnTimeByUserId(userId);

        //旧版兼容处理，如果正在学习中，连麦抛出异常
        String version = Version.getVersion(request);
        if (Version.compareVersion(version, "3.4.0") < 0) {
            UsersVO user = usersService.findOne(userId);
            if (LEARN_TIME_ROOM_LEARNING.code.equals(user.getStatus())) {
                AbstractStudyStatus.checkStatus(UsersStudyInfoDO.TypeEnums.ORDERNARY_COUNT_TIME_START.code, user);
            }
        }

        //TODO
        UsersLearnInfoVO usersLearnInfoVO = new UsersLearnInfoVO();
        usersLearnInfoVO.setLearnTime(jsonObject.getLong("learnTime"));
        usersLearnInfoVO.setLearnStatus(jsonObject.getInteger("learnStatus"));
        UsersLearnTimingDO learnTimingDO = usersStudyService.getUsersLearnTimingByUserId(userId, YN.NO.getCode());
        if (null != learnTimingDO) {
            usersLearnInfoVO.setLearnId(learnTimingDO.getId());
            usersLearnInfoVO.setLearnName(learnTimingDO.getLearnName());
            usersLearnInfoVO.setModel(LearnContentDO.ModelEnum.invalid.code);
            usersLearnInfoVO.setCardList(usersShareService.getCardAvatarList(learnTimingDO.getId()));
            usersLearnInfoVO.setZanList(usersShareService.getZanAvatarList(learnTimingDO.getId()));
            Long contentId = learnTimingDO.getContentId();
            if (Objects.nonNull(contentId)) {
                usersLearnInfoVO.setContentId(contentId);
                LearnContentDO contentDO = usersLearnContentService.findOne(contentId);
                usersLearnInfoVO.setModel(contentDO.getModel());
                usersLearnInfoVO.setMinutes(contentDO.getMinutes());
                if (contentDO.getModel().intValue() == LearnContentDO.ModelEnum.valid.code.intValue() && usersLearnInfoVO.getLearnTime() >= contentDO.getMinutes() * 60L) {
                    usersLearnInfoVO.setLearnTime(contentDO.getMinutes() * 60L);
                    UsersVO usersVO = usersService.findOne(userId);
                    //如果是计时自习室，把房间id和座位id，返回前端
                    if (usersVO.getStatus() == LearningStatus.TIME_LEARN_ROOM.getCode()) {
                        usersLearnInfoVO.setLearnType(1);
                        usersLearnInfoVO.setRoomId(usersVO.getRoomId());
                        usersLearnInfoVO.setSeatId(usersVO.getLianMaiId());
                    }
                }
            }
        } else {
            usersLearnInfoVO.setCardList(new ArrayList<>(0));
            usersLearnInfoVO.setZanList(new ArrayList<>(0));
        }
        return BusinessResult.createSuccessInstance(usersLearnInfoVO);

    }

//    @ApiOperation(value = "学习计时,连麦计时,定时器用", notes = "type:1学习计时,5连麦计时,定时器用，v1.0就这两种计时情况")
//    @PostMapping("/user/job/timing")
//    @AutoLog
//    public BusinessResult jobStudy(@ApiParam(value = "开始学习时间") @RequestParam(required = false) String startTime,
//                                   @ApiParam(value = "结束学习时间") @RequestParam(required = false) String endTime) {
//        asyncTaskManager.getExecutor().submit(() -> {
//            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
//
//            List<UsersDO> byTypeList = usersRepository.findByType(-1);
//            for (UsersDO usersDO : byTypeList) {
//                try {
//                    UsersStudyInfoVO usersStudyInfoVO = new UsersStudyInfoVO();
//                    if (!StringUtil.isEmpty(startTime)) {
//                        Date startDate = simpleDateFormat.parse(startTime);
//                        usersStudyInfoVO.setStartTime(startDate);
//                    }
//                    if (!StringUtil.isEmpty(endTime)) {
//                        Date endDate = simpleDateFormat.parse(endTime);
//                        usersStudyInfoVO.setEndTime(endDate);
//                    }
//                    log.info("开始时间={}， 结束时间={}", usersStudyInfoVO.getStartTime(), usersStudyInfoVO.getEndTime());
//                    usersStudyInfoVO.setUserId(usersDO.getId());
//                    usersStudyInfoVO.setType(11);
//                    if (null == startTime) {
//                        usersStudyInfoVO.setStartTime(CalendarUtil.getCurrentHoursBefore(6 + new Random().nextInt(2)));
//                    }
//                    usersStudyInfoVO.setStudyInfoName("学习计时");
//                    usersStudyInfoVO.setType(UsersStudyInfoDO.TypeEnums.JOB_COUNT_TIME_START.code);
//                    Boolean booleanFuture = usersStudyService.addUsersStudyInfo(usersStudyInfoVO);
//
//                    if (booleanFuture) {
//                        usersStudyInfoVO.setStudyInfoName("学习计时:" + usersDO.getName());
////                                usersStudyInfoVO.setStartTime(CalendarUtil.getCurrentHoursBefore(6+new Random().nextInt(2)));
//                        if (null == endTime) {
//                            usersStudyInfoVO.setEndTime(new Date());
//                        }
//                        usersStudyInfoVO.setUserId(usersDO.getId());
//                        usersStudyInfoVO.setType(1);
//                        usersStudyInfoVO.setType(UsersStudyInfoDO.TypeEnums.JOB_COUNT_TIME.code);
////                                usersStudyInfoVO.setStudyMinuteSeconds(14400+new Random().nextInt(7200));
//                        usersStudyService.addUsersStudyInfo(usersStudyInfoVO);
//                    }
//                } catch (Exception e) {
//                    log.info("学习计时,连麦计时定时器异常 exception={}", e);
//                }
//            }
//        });
//
//        return BusinessResult.createSuccessInstance(null);
//    }


    @ApiOperation(value = "获取入群所有用户学习的总时长之和", notes = "获取用户学习群所有用户入群后的总学习时长之和", response = Integer.class)
    @GetMapping("/users/get/studytime")
    @AutoLog
    @PreAuthorize("isAuthenticated()")
    @AuthSig
    public BusinessResult getGroupStudyTime(@ApiParam(required = true, value = "用户id,逗号隔开，可以传多个用户id") @RequestParam String userIdStr,
                                            @ApiParam(required = true, value = "群创建时间yyyy-MM-dd HH:mm:ss") @RequestParam String createTime
    ) {
        List<Integer> userIdList = Splitter.on(",").omitEmptyStrings().splitToList(userIdStr).stream().map(s -> Integer.parseInt(s.trim())).collect(Collectors.toList());
        if (userIdList.isEmpty()) {
            return BusinessResult.createInstance(PARAMS_NOT_INVALIDE);
        }
        Integer studyMinutes = usersStudyService.getUsersStudyTime(createTime, userIdList);
        return BusinessResult.createSuccessInstance(studyMinutes);

    }

    @ApiOperation(value = "获取群所有用户每天学习时长", notes = "获取群所有用户每天学习时长", response = GroupUserStudyTime.UserDayRepTime.class)
    @PostMapping("/users/day/studytime")
    @AutoLog
    public BusinessResult getGroupUserDayTime(@ApiParam(required = true, value = "用户id每天学习时间VO") @RequestBody GroupUserStudyTime groupUserDayReqTime
    ) {
        try {
            if (null == groupUserDayReqTime || null == groupUserDayReqTime.getUserStudyTimeReqList() || groupUserDayReqTime.getUserStudyTimeReqList().size() == 0) {
                return BusinessResult.createInstance(PARAMS_NOT_INVALIDE);
            }
            List<GroupUserStudyTime.UserDayRepTime> usersDayTimeList = usersStudyService.queryUserDayStudyTime(groupUserDayReqTime);
            return BusinessResult.createSuccessInstance(usersDayTimeList);
        } catch (PlatformException ex) {
            log.error("", ex);
            return BusinessResult.createInstance(CommonResultMessage.UNKOWN_ERROR.code, ex.getMessage(), ex.getMessage());
        } catch (Exception ex) {
            log.error("", ex);
            return BusinessResult.createInstance(CommonResultMessage.UNKOWN_ERROR, "未知异常");
        }
    }


    @ApiOperation(value = "用户学习生活列表，T页面的首页", notes = "用户学习生活列表", response = UsersStudyInfoVO.class)
    @GetMapping("/user/tpage")
    @AutoLog(logLevel = DEBUG)
    @PreAuthorize("isAuthenticated()")
    @AuthSig
    public BusinessResult studyPage(@ApiParam(required = true, value = "用户id") @RequestParam Integer userId,
                                    @ApiParam(value = "页码") @RequestParam(defaultValue = "1") Integer page,
                                    @ApiParam(value = "页码大小") @RequestParam(defaultValue = "20") Integer pageSize) {
        try {
            if (null == userId) {
                return BusinessResult.createInstance(PARAMS_NOT_INVALIDE);
            } else if (null == usersService.find(userId.longValue())) {
                return BusinessResult.createInstance(CommonResultMessage.INVALID_USER);
            }
            PageResultVO<UsersStudyInfoVO> result = null;
            Future<PageResultVO<UsersStudyInfoVO>> future = usersStudyService.getStudyList(userId, page, pageSize);
            result = future.get();
            return BusinessResult.createSuccessInstance(result);
        } catch (PlatformException ex) {
            log.error("", ex);
            return BusinessResult.createInstance(CommonResultMessage.UNKOWN_ERROR.code, ex.getMessage(), ex.getMessage());
        } catch (Exception ex) {
            log.error("", ex);
            return BusinessResult.createInstance(CommonResultMessage.UNKOWN_ERROR, "未知异常");
        }
    }

    @ApiOperation(value = "用户学习生活", notes = "用户学习生活", response = UsersStudyInfoVO.class)
    @GetMapping("/user/studyinfo")
    @AutoLog(logLevel = DEBUG)
    @PreAuthorize("isAuthenticated()")
    @AuthSig
    public BusinessResult learnInfo(@ApiParam(required = true, value = "学习生活日期") @RequestParam String date) {
        try {
            Long currentUserId = currentUserId();
            if (null == currentUserId) {
                return BusinessResult.createInstance(CommonResultMessage.INVALID_USER);
            }
            Future<List<UsersLearnTimingDO>> learnList = usersStudyService.getLearnList(currentUserId, date);
            return BusinessResult.createSuccessInstance(learnList.get(10, TimeUnit.SECONDS));
        } catch (Exception ex) {
            log.error("", ex);
            return BusinessResult.createInstance(CommonResultMessage.UNKOWN_ERROR, "未知异常");
        }
    }

    @ApiOperation(value = "用户学习统计", notes = "用户学UsersStudyInfoDO习统计", response = UserMonthLearnDO.class)
    @GetMapping("/user/studysum")
    @AutoLog(logLevel = DEBUG)
    @PreAuthorize("isAuthenticated()")
    @AuthSig
    public BusinessResult countLearnMonth(@ApiParam(required = false, value = "yyyy-mm，哪个月,默认当月") @RequestParam(required = false) String date) {
        try {
            Long currentUserId = currentUserId();
            if (null == currentUserId) {
                return BusinessResult.createInstance(CommonResultMessage.INVALID_USER);
            }
            return BusinessResult.createSuccessInstance(usersStudyService.getUserMonthLearnTime(currentUserId, date));
        } catch (Exception ex) {
            log.error("", ex);
            return BusinessResult.createInstance(CommonResultMessage.UNKOWN_ERROR, "未知异常");
        }
    }

    @ApiOperation(value = "用户学习统计新V2.4", notes = "用户学习统计新V2.4", response = UserMonthLearnDO.class)
    @GetMapping("/user/sumnew")
    @AutoLog(logLevel = DEBUG)
    @PreAuthorize("isAuthenticated()")
    @AuthSig
    public BusinessResult countLearnMonthNew(@ApiParam(required = false, value = "yyyy-mm，哪个月,默认当月") @RequestParam(required = false) String date) {
        Long currentUserId = currentUserId();
        if (null == currentUserId) {
            return BusinessResult.createInstance(CommonResultMessage.INVALID_USER);
        }
        try {
            return BusinessResult.createSuccessInstance(usersStudyService.countUserLearnTime(currentUserId, date));
        } catch (ParseException e) {
            log.error("", e);
        }
        return BusinessResult.createInstance(CommonResultMessage.UNKOWN_ERROR);
    }

    @ApiOperation(value = "道友每天学习时长排行榜", notes = "道友每天学习时长排行榜")
    @GetMapping("/user/study/ranking")
    @AutoLog(logLevel = DEBUG)
    @PreAuthorize("isAuthenticated()")
    @AuthSig
    public BusinessResult<List<FriendLearnInfoVO>> studyTimesRanking(@ApiParam(required = true, value = "用户id") @RequestParam(required = true) Long userId,
                                                                     @ApiParam(required = false, value = "yyyy-MM-dd") @RequestParam(required = false) String date) {
        try {
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
            if (Objects.isNull(date)) {
                date = simpleDateFormat.format(new Date());
            }
            return BusinessResult.createSuccessInstance(usersStudyService.getDayFriendLearnRanking(userId, date));
        } catch (Exception e) {
            log.error("", e);
        }
        return BusinessResult.createInstance(CommonResultMessage.UNKOWN_ERROR);
    }

    @ApiOperation(value = "用户学习计时，结束学习V2.4.1  步骤一", notes = "用户学习计时，结束学习V2.4.1  步骤一", response = LearnTimeRankVO.class)
    @GetMapping("/user/learn-time/end")
    @AutoLog
    @PreAuthorize("isAuthenticated()")
    @AuthSig
    public BusinessResult endLearnTime() {
        Long userId = currentUserId();
        if (null == userId) {
            return BusinessResult.createInstance(CommonResultMessage.INVALID_USER);
        }
        BusinessResult result = addStudy(UsersStudyInfoVO.builder().type(ORDERNARY_COUNT_TIME.code).userId(userId).build());
        if (result.getCode() == 0) {
            UsersLearningResultVO usersLearningResultVO = (UsersLearningResultVO) result.getData();
            BusinessResult.createSuccessInstance(usersLearningResultVO.getStudyMinutes());
        }
        if (result.getCode().equals(USER_NOT_LEARNING.code)) {
            UsersStudyInfoDO latestStudyInfo = usersStudyService.findLatestStudyInfo(userId);
            UsersLearningResultVO learningResult = usersStudyService.getLearningResult(Objects.requireNonNull(UsersStudyInfoVO.from(latestStudyInfo)));
            return BusinessResult.createSuccessInstance(learningResult);
        }
        return result;
    }

    @ApiOperation(value = "用户学习完成后排名以及变化情况V2.4.1 步骤二", notes = "用户学习完成后排名以及变化情况V2.4.1", response = LearnTimeRankVO.class)
    @GetMapping("/user/learn-time/rank-list")
    @AutoLog
    @PreAuthorize("isAuthenticated()")
    @AuthSig
    public BusinessResult<LearnTimeRankVO> learnTimeRankList() {
        Long userId = currentUserId();
        if (null == userId) {
            return BusinessResult.createInstance(CommonResultMessage.INVALID_USER);
        }
        UsersLearnTimingDO learnTiming = usersStudyService.findLatestLearnTiming(userId);
        List<UserMonthLearnVO.FriendLearnInfo> learnRankList = usersStudyService.getLearnRankList(userId, 0);
        if (learnRankList.size() == 1) {
            return BusinessResult.createSuccessInstance(LearnTimeRankVO.builder().learnRankList(new ArrayList<>()).build());
        }
        UserMonthLearnVO.FriendLearnInfo userRankInfo = learnRankList.stream().filter(rankInfo -> rankInfo.getFriendId().equals(userId)).findFirst().orElseThrow(NullPointerException::new);

        LearnTimeRankVO rank = LearnTimeRankVO.builder().learnRankList(learnRankList)
                .startSort(learnTiming.getStartSort())
                .endSort(userRankInfo.getIndex())
                .build();
        return BusinessResult.createSuccessInstance(rank);
    }

    @ApiOperation(value = "用户学习完成后打卡群完成情况V2.4.1 步骤三", notes = "用户学习完成后打卡群完成情况V2.4.1", response = GroupGoalVO.class)
    @GetMapping("/user/punch-card-group/complete-station")
    @AutoLog
    @PreAuthorize("isAuthenticated()")
    @AuthSig
    public BusinessResult<List<GroupGoalVO>> punchCardGroupCompleteStation() {
        Long userId = currentUserId();
        if (null == userId) {
            return BusinessResult.createInstance(CommonResultMessage.INVALID_USER);
        }

        List<GroupGoalVO> groups = groupInfoService.punchCardGroup(userId).getData();
        log.debug("groups = {}", groups);
        if (Objects.isNull(groups) || groups.isEmpty()) {
            return BusinessResult.createSuccessInstance(new ArrayList<>());
        }

        String date = CalendarUtil.getDateString(CalendarUtil.addOrBeforeNDay(new Date(), 0), CalendarUtil.SHORT_DATE_FORMAT);
        UserDayLearnDO userDayLearnDO = usersStudyService.LatestDayLearnRecord(userId, date);

        log.info("userDayLearnDO = {}", userDayLearnDO);
        if (Objects.isNull(userDayLearnDO)) {
            return BusinessResult.createSuccessInstance(new ArrayList<>());
        }

        groups = groups.stream().peek(group -> {
            group.setLearningDuration(group.getLearningDuration() * 60);
            group.setCompleteMinute(userDayLearnDO.getStudyMinutes().longValue());
        }).sorted(Comparator.comparing(GroupGoalVO::getLearningDuration))
                .collect(Collectors.toList());
        for (int i = 0; i < groups.size(); i++) {
            groups.get(i).setIndex(i + 1);
        }
        return BusinessResult.createSuccessInstance(groups);
    }

    @ApiOperation(value = "用户学习完成后学习生活情况V2.4.1 步骤四", notes = "用户学习完成后学习生活情况V2.4.1", response = GroupGoalVO.class)
    @GetMapping("/user/learn-time/study-info")
    @AutoLog
    @PreAuthorize("isAuthenticated()")
    @AuthSig
    public BusinessResult<UsersLearningResultVO> studyInfo() {
        Long userId = currentUserId();
        if (null == userId) {
            return BusinessResult.createInstance(CommonResultMessage.INVALID_USER);
        }
        UsersLearningResultVO learningResult = usersStudyService.getLearningResult(userId);
        return BusinessResult.createSuccessInstance(learningResult);
    }

    @ApiOperation(value = "备注本次连麦学习", notes = "备注本次连麦学习", response = UsersStudyInfoDO.class)
    @AutoLog
    @PreAuthorize("isAuthenticated()")
    @AuthSig
    @PutMapping("/user/learn-time/study-info/study-name/{studyName}")
    public BusinessResult<UsersStudyInfoDO> updateStudyName(@PathVariable String studyName) {
        Long userId = currentUserId();
        if (null == userId) {
            return BusinessResult.createInstance(CommonResultMessage.INVALID_USER);
        }
        UsersLearnTimingDO latestLearnTiming = usersStudyService.findLatestLearnTiming(userId);
        latestLearnTiming.setLearnName(studyName);
        usersStudyService.saveUsersLearnTiming(latestLearnTiming);
        UsersStudyInfoDO latestStudyInfo = usersStudyService.findLatestStudyInfo(userId);
        usersStudyService.saveLearnName(userId, studyName);
        return BusinessResult.createSuccessInstance(usersStudyService.update(latestStudyInfo));
    }


    @ApiOperation(value = "用户学习完成后学习生活情况V2.4.1 分享图片", notes = "用户学习完成后学习生活情况V2.4.1 分享图片")
    @GetMapping("/user/learn-time/study-info/picture")
    @AutoLog
    @PreAuthorize("isAuthenticated()")
    @AuthSig
    public BusinessResult<String> studyPicture() {
        Long userId = currentUserId();
        String content = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=wxeb6be10fec237b67&redirect_uri=" + url + "/tz-user-center/users/invite&response_type=code&scope=snsapi_userinfo&state=" + userId + ",3&connect_redirect=1&friendsType=1";
        if (null == userId) {
            return BusinessResult.createInstance(CommonResultMessage.INVALID_USER);
        }
        UsersStudyInfoDO latestStudyInfo = usersStudyService.findLatestStudyInfo(userId);
        UsersLearningResultVO learningResult = usersStudyService.getLearningResult(Objects.requireNonNull(UsersStudyInfoVO.from(latestStudyInfo)));
        try {
            int index = getRandom(0, 2);
            byte[] drawQrcode = QrcodeUtils.drawQrcode(content, 100, 100);
            byte[] logoToQRCode = QrcodeUtils.addLogoToQRCode(drawQrcode, QrcodeUtils.getLogo(), new LogoConfig());
            //二维码文字的位置
            List<QrcodeFont> qrCodeFontList = getQrcodeFonts(learningResult.getTodayHours().toString(), learningResult.getStudyDays(), index);

            File pressText = QrcodeUtils.pressText(logoToQRCode, QrcodeUtils.getBg(index), 686, 788, qrCodeFontList);
            String url = uploadService.uploadOssFile(pressText, MODEL_PATH, "user/learn", false);

            return BusinessResult.createSuccessInstance(url);
        } catch (Exception e) {
            log.error("", e);
        }
        return null;
    }

    public static int getRandom(int start, int end) {
        return (int) (Math.random() * (end - start + 1) + start);
    }


    @AutoLog
    @ApiOperation(value = "微信扫码加好友邀请", notes = "微信扫码加好友邀请", position = 121)
    @GetMapping("/user/learn-time/share")
    @AuthSig
    public void share(@RequestParam Long userId, HttpServletResponse response) throws IOException {
        UsersVO users = usersService.find(userId);
        //前端展示页面
        String appShareUrl = "http://img.sunlands.wang/deskmateApp/index/invitation.html?ids=" + userId + ",type=2&name=" + users.getName() + "&avater=" + users.getAvatarUrl() + "&target=" + users.getCurrentLearnTargetName() + "&from=singlemessage&isappinstalled=0";
        response.sendRedirect(appShareUrl);
    }

    private List<QrcodeFont> getQrcodeFonts(String todayHours, Integer studyDays, Integer index) {
        List<PicEnum> pics = Arrays.stream(PicEnum.values()).collect(Collectors.toList());
        PicEnum pic = pics.get(index);

        List<QrcodeFont> qrCodeFontList = new ArrayList<>();
        QrcodeFont font1 = new QrcodeFont();
        font1.setStartX(pic.getStartX1());
        font1.setStartY(pic.getStartY1());
        font1.setColor(Color.BLACK);
        font1.setText(todayHours + "小时");
        font1.setFontSize(32);
        qrCodeFontList.add(font1);

        QrcodeFont font2 = new QrcodeFont();
        font2.setStartX(pic.getStartX2());
        font2.setStartY(pic.getStartY2());
        font2.setColor(Color.BLACK);
        font2.setText(studyDays + "天");
        font2.setFontSize(32);
        qrCodeFontList.add(font2);
        return qrCodeFontList;
    }

    @Autowired
    private UploadService uploadService;


    @ApiOperation(value = "用户学习统计V2.4,旧数据处理", notes = "用户学习统计V2.4，旧数据处理")
    @GetMapping("/user/sumold")
    @AutoLog(logLevel = DEBUG)
    @AuthSig
    public BusinessResult counOldMonthData(@ApiParam(required = true, value = "开始日期") @RequestParam String startTime,
                                           @ApiParam(required = true, value = "结束日期") @RequestParam String endTime,
                                           @ApiParam(required = true, value = "学习类型") @RequestParam Integer type) {
        try {
            usersStudyService.refreshOldMonthData(startTime, endTime, type);
            return BusinessResult.createSuccessInstance("OK");
        } catch (Exception ex) {
            log.error("", ex);
            return BusinessResult.createInstance(CommonResultMessage.UNKOWN_ERROR, "未知异常");
        }
    }


    @ApiOperation(value = "用户学习计时列表，计时契约群用", notes = "用户学习计时列表，计时契约群用", response = UsersLearnTimingVO.class)
    @GetMapping("/user/learntiming/page")
    @AutoLog(logLevel = DEBUG)
    public BusinessResult learnTimingPage(@ApiParam(required = true, value = "用户id") @RequestParam Integer userId,
                                          @ApiParam(required = true, value = "上一页最后一条记录id,首页tailId传0") @RequestParam Integer tailId,
                                          @ApiParam(value = "页码") @RequestParam(defaultValue = "1") Integer page,
                                          @ApiParam(value = "页码大小") @RequestParam(defaultValue = "20") Integer pageSize) {
        try {
            if (null == userId) {
                return BusinessResult.createInstance(PARAMS_NOT_INVALIDE);
            } else if (null == usersService.find(userId.longValue())) {
                return BusinessResult.createInstance(CommonResultMessage.INVALID_USER);
            }
            PageResultVO<UsersLearnTimingVO> usersLearnTimingVOPageResultVO = usersStudyService.getLearnTimingList(userId, tailId, page, pageSize);
            return BusinessResult.createSuccessInstance(usersLearnTimingVOPageResultVO);
        } catch (PlatformException ex) {
            log.error("", ex);
            return BusinessResult.createInstance(CommonResultMessage.UNKOWN_ERROR.code, ex.getMessage(), ex.getMessage());
        } catch (Exception ex) {
            log.error(" ", ex);
            return BusinessResult.createInstance(CommonResultMessage.UNKOWN_ERROR, "未知异常");
        }
    }

    @ApiOperation(value = "用户学习计时push", notes = "用户学习计时push")
    @GetMapping("/push")
    @AutoLog
    @PreAuthorize("isAuthenticated()")
    @AuthSig
    @Deprecated
    public BusinessResult push(@ApiParam(required = true, value = "用户id") @RequestParam Long userId) {
        try {
            if (null == userId) {
                return BusinessResult.createInstance(PARAMS_NOT_INVALIDE);
            }
            UsersVO usersVO = usersService.find(userId);
            if (null == usersVO) {
                return BusinessResult.createInstance(CommonResultMessage.INVALID_USER);
            }

            PushDTO pushDTO = PushDTO.builder().content("您预订的计时时间已到").type(1).ids(Lists.newArrayList(userId + "")).build();
            JSONObject jsonObject = deskMatePushService.push(pushDTO);
            if (null == jsonObject || null == jsonObject.getInteger("code") || 0 != jsonObject.getInteger("code")) {
                throw new CheckRunException("push系统异常");
            }
            return BusinessResult.createSuccessInstance("ok");
        } catch (PlatformException ex) {
            log.error("", ex);
            return BusinessResult.createInstance(CommonResultMessage.UNKOWN_ERROR.code, ex.getMessage(), ex.getMessage());
        } catch (Exception ex) {
            log.error("", ex);
            return BusinessResult.createInstance(CommonResultMessage.UNKOWN_ERROR, "未知异常");
        }
    }


    @ApiOperation(value = "用户总连麦时长", notes = "用户总连麦时长")
    @GetMapping("/live/total/time")
    @AutoLog
    @PreAuthorize("isAuthenticated()")
    @AuthSig
    public BusinessResult<Integer> totalLiveMinute(@ApiParam(required = true, value = "用户id") @RequestParam Long userId) {
        return BusinessResult.createSuccessInstance(usersStudyService.totalLiveMinute(userId));
    }

    private String checkAddStudy(UsersStudyInfoVO usersStudyInfoVO) {
        if (null == usersStudyInfoVO) {
            return "学习VO不能为空";
        } else if (null == UsersStudyInfoDO.TypeEnums.create(usersStudyInfoVO.getType())) {
            return "学习类型错误";
        } else if (null == usersStudyInfoVO.getUserId()) {
            return "用户id不能为空！";
        }
        return null;
    }

    @Autowired
    @Lazy
    private UsersStudyServiceImpl usersStudyService;
    @Autowired
    @Lazy
    private GroupInfoService groupInfoService;
    @Autowired
    private DeskMatePushService deskMatePushService;
    @Autowired
    @Lazy
    private UsersServiceImpl usersService;
    @Autowired
    private UsersShareServiceImpl usersShareService;
    @Autowired
    private RedisDistributedLockImpl redisDistributedLock;
    @Autowired
    private UsersLearnContentServiceImpl usersLearnContentService;
    @Autowired
    private RedisTemplate redisTemplate;
    private final UsersRepository usersRepository;
    private final AsyncTaskManager asyncTaskManager;

    public UsersStudyController(UsersRepository usersRepository, AsyncTaskManager asyncTaskManager) {
        this.usersRepository = usersRepository;
        this.asyncTaskManager = asyncTaskManager;
    }

}
